﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Xml;

namespace ShiQuan.AppUpdater.Helper
{
    /// <summary>
    /// 执行委托
    /// </summary>
    /// <param name="index"></param>
    /// <param name="msg"></param>
    public delegate void OnProcess(int index,string msg);
    /// <summary>
    /// 程序更新业务
    /// </summary>
    public class AppUpdateBLL
    {
        /// <summary>
        /// 开始
        /// </summary>
        public event OnProcess StartProcess = null;
        /// <summary>
        /// 执行中
        /// </summary>
        public event OnProcess UpdateProcess = null;
        /// <summary>
        /// 结束
        /// </summary>
        public event OnProcess CloseProcess = null;
        /// <summary>
        /// 本地程序信息文件
        /// </summary>
        public static string AppLocalFile = string.Empty;

        /// <summary>
        /// 压缩包中的本地程序信息文件
        /// </summary>
        public static string AppZipFile = string.Empty;
        /// <summary>
        /// 获取本地程序信息
        /// </summary>
        /// <param name="appPath"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static AppLocalInfo GetLocalInfo(string appPath,out string error)
        {
            error = string.Empty;
            Logger.Info("开始检查更新...");
            if (string.IsNullOrEmpty(appPath))
                appPath = System.IO.Directory.GetParent(Application.StartupPath).FullName;

            //string mParentPath = System.IO.Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory);
            //读取本地程序信息
            AppLocalFile = System.IO.Path.Combine(appPath, "AppUpdater.xml");
            if (System.IO.File.Exists(AppLocalFile) == false)
            {
                error = "未能找到配置:" + AppLocalFile;
                Logger.Error(error);
                return null;
            }
            AppLocalInfo appLocalInfo = new AppLocalInfo();
            appLocalInfo.InitValue(AppLocalFile);
            return appLocalInfo;
        }
        /// <summary>
        /// 获取服务器程序信息
        /// </summary>
        /// <param name="serverurl"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static AppServerInfo GetServerInfo(string serverurl,out string error)
        {
            error = string.Empty;
            Logger.Info("下载服务器程序信息：" + serverurl);
            //获取服务器程序信息
            var mAppServerInfo = WebClientHelper.Get(serverurl);
            if (string.IsNullOrEmpty(mAppServerInfo))
            {
                error = "未能获取到服务器程序信息！";
                Logger.Error(error);
                return null;
            }
            Logger.Info("下载结果：" + mAppServerInfo);
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(mAppServerInfo);
            AppServerInfo appServerInfo = new AppServerInfo();
            appServerInfo.InitValue(doc);
            return appServerInfo;
        }
        /// <summary>
        /// 检查是否需要更新
        /// </summary>
        /// <param name="appPath"></param>
        public static bool Check(AppLocalInfo appLocalInfo,AppServerInfo appServerInfo)
        {
            //判断是否有更新程序下载
            Logger.Info("本地程序版本：" + appLocalInfo.Version + " 服务器程序版本：" + appServerInfo.Version);
            long mLocalVersion = 0, mServerVersion = 0;

            long.TryParse(appLocalInfo.Version.Replace(".", ""), out mLocalVersion);

            long.TryParse(appServerInfo.Version.Replace(".", ""), out mServerVersion);

            return mServerVersion > mLocalVersion;
        }
        /// <summary>
        /// 下载更新程序
        /// </summary>
        /// <param name="localInfo"></param>
        /// <param name="serverInfo"></param>
        public void Update(AppLocalInfo localInfo,AppServerInfo serverInfo)
        {
            string error = string.Empty;
            string mPackName = string.Empty;
            string mSaveFile = string.Empty;
            try
            {
                //判断是否需要关闭进程及服务程序
                this.AppendText(1, "判断是否需要关闭进程程序..." + localInfo.KillProcess);
                if (string.IsNullOrEmpty(localInfo.KillProcess) == false)
                {
                    string[] mKillProcess = localInfo.KillProcess.Split(';');
                    for (int index = 0; index < mKillProcess.Length; index++)
                    {
                        WinProcessHelper.Kill(mKillProcess[index]);
                        if(WinProcessHelper.Exists(mKillProcess[index]))
                        {
                            this.AppendText(100, "无法关闭应用程序:" + mKillProcess[index]);
                            return;
                        }   
                    }
                }
                this.AppendText(5, "判断是否需要关闭服务程序..." + localInfo.StopServices);
                if (string.IsNullOrEmpty(localInfo.StopServices) == false)
                {
                    string[] mStopServices = localInfo.StopServices.Split(';');
                    WinServiceHelper.Stop(mStopServices);
                }

                //下载更新程序
                this.AppendText(10, "下载更新程序包:" + serverInfo.FileUrl);
                mPackName = System.IO.Path.GetFileNameWithoutExtension(serverInfo.FileUrl);
                mSaveFile = System.IO.Path.Combine(Application.StartupPath, mPackName + ".zip");
                bool result = WebClientHelper.Download(serverInfo.FileUrl, mSaveFile, out error);
                if (result == false)
                {
                    this.AppendText(100, error);
                    return;
                }
                //解压更新程序文件
                this.AppendText(20, "解压更新程序文件:" + mSaveFile);
                ZipFileHelper.DeCompress(mSaveFile, Application.StartupPath);
            }
            catch (Exception ex)
            {
                this.AppendText(100, "下载更新程序包异常:" + ex.ToString());
                return;
            }
            string appPath = string.Empty;
            try
            {
                appPath = System.IO.Directory.GetParent(Application.StartupPath).FullName;
                //更新文件
                this.AppendText(50, "更新文件..."+appPath);
                string mPackPath = System.IO.Path.Combine(Application.StartupPath, mPackName);
                ZipFileHelper.Copy(mPackPath, appPath);
                //删除目录
                System.IO.Directory.Delete(mPackPath, true);
                //删除文件
                System.IO.File.Delete(mSaveFile);
            }
            catch (Exception ex)
            {
                this.AppendText(100, "更新程序文件异常:" + ex.ToString());
                return;
            }
            try
            {
                //重新获取本地程序信息
                this.AppendText(80, "重新获取本地程序信息...");
                localInfo = AppUpdateBLL.GetLocalInfo(appPath, out error);
                if (localInfo == null)
                {
                    this.AppendText(100, "本地程序信息为空："+error);
                    return;
                }
                //判断是否需要重启程序及服务程序
                this.AppendText(90, "判断是否需要重启程序及服务程序..." + localInfo.StartServices);
                if (string.IsNullOrEmpty(localInfo.StartServices) == false)
                {
                    string[] mStartServices = localInfo.StartServices.Split(';');
                    WinServiceHelper.Stop(mStartServices);
                }

                this.AppendText(90, "判断是否需要重启程序及服务程序..."+ localInfo.StartProcess);
                if (string.IsNullOrEmpty(localInfo.StartProcess) == false)
                {
                    string[] mStartProcess = localInfo.StartProcess.Split(';');
                    foreach (var item in mStartProcess)
                    {
                        string appFile = System.IO.Path.Combine(appPath, item + ".exe");
                        WinProcessHelper.Start(appFile);
                    }
                }
                this.AppendText(100, "完成程序更新！");
            }
            catch (Exception ex)
            {
                this.AppendText(100, "判断启动程序异常:" + ex.ToString());
            }
        }

        private void AppendText(int index,string msg)
        {
            Logger.Info(msg);
            if (this.UpdateProcess != null)
                this.UpdateProcess(index, msg);
        }
    }
}
